﻿// --------------------------------------------------------------------------------------------------------------------
// <copyright file="Signaller.cs" company="R.V.Kasner">
//   Copyright © 2011 R.V.Kasner
// </copyright>
// --------------------------------------------------------------------------------------------------------------------

namespace Owen.Communication.Service
{
    using System;

    using Owen.Communication.Serial;

    public sealed class Signaller : ISignaller
    {
        private readonly ISerialPort portShell;

        private readonly IReceiver receiver;

        private readonly ITransmitter transmitter;

        public Signaller(ISerialPort portShell, ITransmitter transmitter, IReceiver receiver)
        {
            this.portShell = portShell;
            this.transmitter = transmitter;
            this.receiver = receiver;
            this.receiver.Stoped += this.OnReceiverStoped;

            this.receiver.Started += this.RaiseStatesChanged;
            this.receiver.Stoped += this.RaiseStatesChanged;
            this.transmitter.Started += this.RaiseStatesChanged;
            this.transmitter.Stoped += this.RaiseStatesChanged;
        }

        public event Action<int[]> Received
        {
            add
            {
                this.receiver.Received += value;
            }

            remove
            {
                this.receiver.Received -= value;
            }
        }

        public event Action Started;

        public event Action<SignallerStates> StatesChanged;

        public event Action Stoped;

        public event Action<int[]> Transmited
        {
            add
            {
                this.transmitter.Transmited += value;
            }

            remove
            {
                this.transmitter.Transmited -= value;
            }
        }

        public bool IsRunning
        {
            get
            {
                return this.portShell.IsOpen;
            }
        }

        public bool IsTransmitting
        {
            get
            {
                return this.transmitter.IsRunning;
            }
        }

        public void Start(PortSettings portSettings)
        {
            this.portShell.PortName = portSettings.PortName;
            this.portShell.Parity = portSettings.Parity;
            this.portShell.DataBits = (int)portSettings.DataBits;
            this.portShell.StopBits = portSettings.StopBits;
            this.portShell.Handshake = portSettings.Handshake;
            this.portShell.BaudRate = portSettings.BaudRate;
            this.portShell.ReadTimeout = portSettings.ReadTimeout;

            this.portShell.Open();
            this.receiver.Start();

            this.RaiseStarted();
            this.RaiseStatesChanged();
        }

        public void Stop()
        {
            if (this.transmitter.IsRunning) this.transmitter.Stop();

            this.receiver.Stop();
        }

        public void Transmit(ITransferHead head)
        {
            this.transmitter.Start(head);
        }

        public void TransmitStop()
        {
            this.transmitter.Stop();
        }

        private void OnReceiverStoped()
        {
            this.portShell.Close();
            this.RaiseStoped();
        }

        private void RaiseStarted()
        {
            var handler = this.Started;
            if (handler != null) handler();
        }

        private void RaiseStatesChanged()
        {
            var ss = SignallerStates.Close;
            if (this.transmitter.IsRunning) ss |= SignallerStates.Transmit;
            if (this.receiver.IsRunning) ss |= SignallerStates.Reseive;
            if (this.IsRunning) ss |= SignallerStates.Open;

            var handler = this.StatesChanged;
            if (handler != null) handler(ss);
        }

        private void RaiseStoped()
        {
            var handler = this.Stoped;
            if (handler != null) handler();
        }
    }
}